from django.conf import settings
from django.contrib.auth.hashers import make_password
from django.db.models import Q

from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from rest_framework_jwt.settings import api_settings

from utils.get_name import choice_name
from utils.my_print import new_print
from utils.update_password import set_new_password

jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
from django.core.cache import cache

from . import models
from utils.md5_password import md5


class CommLoginBase:
    """
    登录基类
    """

    def _get_user(self, attrs):
        """
        获取用户
        :return:
        """
        raise ValidationError('重写')

    def get_token(self, user):
        """
        签发token
        :return:
        """
        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)
        return token

    def validate(self, attrs):
        """
        进行校验
        :param attrs:
        :return:
        """
        # 获取用户
        user = self._get_user(attrs)
        token = self.get_token(user)
        self.context['username'] = user.username
        self.context['token'] = token
        self.context['icon'] = settings.BASE_URL + user.icon.name
        return attrs

    def _check_code(self, attrs):
        """
        检测手机号
        :param attrs:
        :return:
        """
        mobile = attrs.get('mobile')
        code = attrs.get('code')
        cache_code = cache.get('send_sms_code_%s' % mobile)
        if str(code) == str(cache_code) or (settings.DEBUG == True and str(code) == '8888'):
            return mobile
        raise ValidationError('验证码错误')


class CommRegisterBase:
    """
    注册基类
    """

    def _check_code(self, attrs):
        """
        检测手机号
        :param attrs:
        :return:
        """
        mobile = attrs.get('mobile')
        code = attrs.get('code')
        cache_code = cache.get('send_sms_code_%s' % mobile)
        if str(code) == str(cache_code) or (settings.DEBUG == True and str(code) == '8888'):
            print('>>>>>')
            return True
        raise ValidationError('验证码错误')

    def validate(self, attrs):
        # 校验手机号
        self._check_code(attrs)

        return attrs

    def create(self, validated_data):
        raise ValidationError('必须重写')


class MultiLoginNModelSerializer(CommLoginBase, serializers.ModelSerializer):
    """
    多方式登录
    """
    username = serializers.CharField()

    class Meta:
        model = models.User
        fields = ['username', 'password']

    def _get_user(self, attrs):
        """
        获取用户
        :return:
        """
        username = attrs.get('username')
        password = attrs.get('password')

        try:
            user_obj = models.User.objects.get(Q(username=username) | Q(email=username) | Q(mobile=username))
            if user_obj and user_obj.check_password(password):
                return user_obj
            raise ValidationError('用户不存在')
        except Exception:
            raise ValidationError('用户不存在')


class SmsLoginNModelSerializer(CommLoginBase, serializers.ModelSerializer):
    """
    短信登录
    """
    mobile = serializers.CharField(allow_null=False)
    code = serializers.CharField(allow_null=False, max_length=4, min_length=4)

    class Meta:
        model = models.User
        fields = ['mobile', 'code']

    def _get_user(self, attrs):
        """
        获取用户
        :return:
        """
        # mobile = attrs.get('mobile')
        # code = attrs.get('code')
        #
        # cache_code = cache.get('send_sms_code_%s' % mobile)
        #
        # if str(code) == str(cache_code) or (settings.DEBUG == True and str(code) == '8888'):
        mobile = self._check_code(attrs)
        if mobile:
            user_obj = models.User.objects.get(mobile=mobile)
            return user_obj
        raise ValidationError('验证码错误')


class SmsRegisterModelSerializer(CommRegisterBase, serializers.ModelSerializer):
    """
    短信注册
    """
    code = serializers.CharField(required=True, max_length=4, min_length=4)

    class Meta:
        model = models.User
        fields = ['mobile', 'code', 'password']

    def create(self, validated_data):
        """
        保存
        :param validated_data:
        :return:
        """
        # 抛掉code
        validated_data.pop('code')
        # 用户名随机生成
        name = choice_name()
        validated_data['username'] = name
        user = models.User.objects.create_user(**validated_data)
        return user


class SmsOnClickLoginNModelSerializer(CommRegisterBase, serializers.ModelSerializer):
    """
    一键注册
    """
    code = serializers.CharField(required=True, max_length=4, min_length=4)

    class Meta:
        model = models.User
        fields = ['mobile', 'code']

    def create(self, validated_data):
        # 抛掉code
        validated_data.pop('code')
        # 用户名随机生成
        name = choice_name()
        password = 'Password must be modified'
        validated_data['username'] = name
        validated_data['password'] = password
        user = models.User.objects.create(**validated_data)
        return user


class SmsUpdatePasswordModelSerializer(CommLoginBase, serializers.ModelSerializer):
    """
    修改密码
    """
    mobile = serializers.CharField(required=True)
    code = serializers.CharField(required=True, max_length=4, min_length=4)
    password = serializers.CharField(required=True)

    class Meta:
        model = models.User
        fields = ['mobile', 'code', 'password']

    def _get_user(self, attrs):
        """
        获取用户
        :return:
        """
        password = attrs.get('password')
        # 校验验证码
        mobile = self._check_code(attrs)
        # try:
        # 查询记录
        user_obj = models.User.objects.get(mobile=mobile)
        new_print(user_obj)
        # 最开始的密码
        old_password = user_obj.password
        # 新密码
        new_password = md5(password)

        print('old_password：', old_password)
        print('new_password：', new_password)

        # 判断密码表里面是否有记录
        user_password_query = models.UserPassword.objects.filter(user=user_obj)
        # 如果为空，直接保存
        if not user_password_query.exists():
            # 新增加记录
            models.UserPassword.objects.create(user=user_obj, password=new_password)
            return user_obj

        # if old_password == new_password:
        #     raise ValidationError('新密码不能跟旧密码相同')

        # 保证密码不能一致
        for item in user_password_query:
            # print(new_password, '>>>new_password>>')
            # print(item.password, '>>item.password>>>')
            if new_password == item.password:
                raise ValidationError('密码不能跟前三次的一致')
        # 如果密码不存在,但是用户存在，说明没有改过密码，直接修改即可
        if user_password_query.count() < 3:
            # 返回新密码
            # 新增加记录
            models.UserPassword.objects.create(user=user_obj, password=new_password)
            return user_obj

        # todo user表也要改，userpassword表也要改
        # 最近的一条替换

        last_user_obj = models.UserPassword.objects.filter(user=user_obj).all().order_by('-updated_time')[0:3][2]
        # print('last_user_obj', last_user_obj)
        last_user_obj.password = new_password
        last_user_obj.save()
        # print(last_user_obj, '>>>>>>')

        return user_obj

        # except Exception:
        #     raise ValidationError('密码非法，不能与之前的一致')
